iT邦幫忙

2025 iThome 鐵人賽

DAY 27
1

聯繫我

如果有任何問題或建議,歡迎隨時聯繫我:

前言

功能再強大的應用,如果操作起來卡頓、遲緩,也會讓使用者失去耐心,最終選擇離開。效能不是一個錦上添花的功能,它是使用者體驗的基石。

打個比方:一位頂級大廚為你準備了十道菜的豪華盛宴(你的應用功能),但每道菜之間都要等一個小時才能上桌(糟糕的效能)。無論菜餚多麼美味,這次用餐體驗注定是失敗的。使用者(食客)早就餓著肚子走人了。

Vue 本身已經是一個效能怪獸,它的響應式系統和 Virtual DOM 演算法都經過了高度優化。但在開發複雜應用的過程中,我們還是可能在不經意間製造出效能瓶頸。

今天,我們不談空泛的理論,只分享三個在實戰中立竿見影的 Vue 效能優化技巧:keep-alivev-memo虛擬滾動。學會它們,你就能像個外科醫生一樣,精準地切除應用的效能頑疾。

1. <keep-alive>:為你的元件提供「記憶」

  • 問題場景:在一個常見的後台管理介面,你可能有多個頁籤,例如「使用者列表」和「訂單列表」。當你從「使用者列表」切換到「訂單列表」時,Vue 預設會銷毀「使用者列表」這個元件。當你再切換回來時,Vue 會重新建立一個全新的「使用者列表」元件。這會導致:

    1. 元件狀態遺失(例如滾動條位置、表單輸入內容)。
    2. 觸發不必要的 API 重新請求。
    3. 浪費渲染效能。
  • 解決方案:使用 Vue 內建的 <keep-alive> 元件。

  • 比喻<keep-alive> 就像是給你的元件一顆「記憶膠囊」。吃了它之後,元件在被切換掉時不會「死亡」,而是進入「休眠」狀態。當你再次需要它時,它能立刻從休眠中醒來,完美地恢復到離開前的所有狀態。

  • 如何使用:最常見的用法是包覆在 <router-view> 外面。

    // App.vue
    <router-view v-slot="{ Component }">
      <keep-alive>
        <component :is="Component" />
      </keep-alive>
    </router-view>
    
  • 進階控制:你可以使用 includeexclude props,來精準控制哪些元件需要被快取。

    <!-- 只快取名稱為 UserList 或 OrderList 的元件 -->
    <keep-alive :include="['UserList', 'OrderList']">
      <component :is="Component" />
    </keep-alive>
    
  • 生命週期:被 <keep-alive> 包覆的元件,會多出兩個新的生命週期鉤子:onActivated(元件被啟用時)和 onDeactivated(元件被停用時),讓你可以在元件「睡著」和「醒來」時執行特定邏輯。

2. v-memo:給 VDOM 更新踩煞車

  • 問題場景:在你的元件中,有一塊區域內容非常複雜,或是一個超長的 v-for 列表。當元件因為其他部分更新而需要重新渲染時,Vue 依然會為這塊複雜的區域建立新的 VNode,並進行比對,即使這塊區域的資料根本沒有改變。

  • 解決方案:使用 v-memo 指令,手動告訴 Vue:「嘿,只有在這些特定資料改變時,才需要更新這塊區域。」

  • 比喻v-memo 就像是在你模板的某個區塊掛上一個「請勿打擾」的牌子。每次 Vue 重新渲染路過這裡時,它會先看一下牌子上的條件。如果條件沒變,Vue 就會直接跳過,不去打擾這個區塊和它所有的子孫,從而節省大量的渲染開銷。

  • 如何使用v-memo 接收一個依賴陣列。只有當陣列中的值發生變化時,這個元素及其子樹才會被更新。

    <!-- 假設我們在渲染一個超長的部落格文章列表 -->
    <!-- 只有當 post.isUpdated 改變時,這個 <div> 才會重新渲染 -->
    <div v-for="post in posts" :key="post.id" v-memo="[post.isUpdated]">
      <h3>{{ post.title }}</h3>
      <p>{{ post.content }}</p>
      <!-- 這裡可能還有很多很多子元件 -->
    </div>
    
  • 重要提醒v-memo 是一個微觀層級的優化。不要濫用它!它主要適用於 v-for 中渲染大量節點(例如 > 100 個),且你希望精準控制哪些列表項需要更新的場景。對於絕大多數情況,Vue 預設的 VDOM diff 演算法已經足夠快了。

3. 虛擬滾動 (Virtual Scrolling):只渲染你看到的

  • 問題場景:如果 v-memo 還不夠用呢?當你需要渲染一個包含數千、數萬甚至數百萬筆資料的列表時,即使有 v-memo,一次性渲染這麼多 DOM 節點也會直接讓瀏覽器崩潰。

  • 解決方案虛擬滾動 (也稱「視窗化」Windowing)。

  • 比喻:虛擬滾動就像一個魔術師的障眼法。觀眾(使用者)以為自己看到的是一整副無限長的撲克牌(整個列表),但實際上,魔術師(渲染引擎)手中永遠只拿著眼前的那幾張牌。當使用者向上滾動時,魔術師就巧妙地把最下面的牌換成即將出現的新牌,並把它放到最上面。

  • 核心原理:只渲染當前可視範圍 (Viewport) 內的列表項,以及在上下方預留一小部分緩衝區。隨著使用者滾動,動態地更新和回收 DOM 節點,使得無論列表有多長,實際渲染在頁面上的 DOM 元素始終只有一小部分。

  • 如何使用:這是一個相對複雜的技術,我們通常不會自己從零開始寫,而是使用成熟的第三方庫。

    <!-- 使用 vue-virtual-scroller 的概念性範例 -->
    <RecycleScroller
      class="scroller"
      :items="massiveList"
      :item-size="32" <!-- 每個列表項的高度 -->
      v-slot="{ item }"
    >
      <div class="list-item">{{ item.name }}</div>
    </RecycleScroller>
    

本篇自我挑戰

  1. 體驗 <keep-alive>:在你的專案中,找到一個使用 <router-view> 的地方,用 <keep-alive> 包覆它。打開開發者工具的 Network 頁籤,觀察在切換路由時,API 請求是否還會被重複觸發?
  2. 探索虛擬滾動:(選做) 安裝 vue-virtual-scroller,並嘗試用它渲染一個包含 10,000 個物件的陣列。感受一下它驚人的流暢度。
  3. 使用 Vue Devtools:打開 Vue 開發者工具的「Performance」頁籤,它可以幫你分析元件的渲染耗時,是尋找效能瓶頸的利器。

總結

今天我們學習了三種強大的 Vue 執行期效能優化武器:

  • <keep-alive>:透過快取元件實例,避免不必要的銷毀和重建,適用於頁籤式導覽。
  • v-memo:一個微觀優化工具,用於跳過大型靜態內容的 VDOM 比對,適用於超長列表的精準更新。
  • 虛擬滾動:處理海量資料列表的終極方案,確保流暢的滾動體驗。

效能優化是一個持續的過程,而不是一次性的任務。將這些技巧收入你的工具箱,並在適當的時機使用它們,你的 Vue 應用將會感謝你。

明天,我們將探討另一個與效能息息相關的主題:如何透過 Code Splitting (程式碼分割) 來優化我們應用的初始載入速度。

本日關鍵字回顧

  • 執行期效能 (Runtime Performance)
  • <keep-alive>
  • onActivated / onDeactivated
  • v-memo
  • 記憶化 (Memoization)
  • 虛擬滾動 (Virtual Scrolling)
  • 視窗化 (Windowing)
  • vue-virtual-scroller
  • TanStack Virtual
  • Vue 開發者工具 (Vue Devtools)

上一篇
【Day 26】測試金字塔:單元、整合與 E2E 測試的權衡
下一篇
【Day 28】縮小你的首屏負擔:Code Splitting 與 Lazy Loading
系列文
Vue 全攻略:30 天技能樹養成30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言